package com.cyy.model

import cn.hutool.core.io.FileUtil
import cn.hutool.core.util.ReflectUtil
import com.jfinal.kit.Kv
import com.jfinal.plugin.activerecord.Config
import com.jfinal.plugin.activerecord.Db
import com.jfinal.plugin.activerecord.DbKit
import com.jfinal.plugin.activerecord.DbPro
import com.jfinal.plugin.activerecord.dialect.*
import com.jfinal.plugin.activerecord.generator.MetaBuilder
import com.jfinal.plugin.activerecord.generator.TypeMapping
import com.jfinal.template.Directive
import com.jfinal.template.Engine
import com.jfinal.template.Env
import com.jfinal.template.Template
import com.jfinal.template.expr.ast.ExprList
import com.jfinal.template.io.Writer
import java.io.File
import java.io.FileWriter
import java.sql.Connection
import java.util.*
import javax.sql.DataSource
import javax.swing.filechooser.FileSystemView
import kotlin.collections.ArrayList

//import javax.sql.DataSource

object Constants {
    fun closeDb(ds: DataSource) {
        try {
            ds.connection.close()
            println("db connection close success")
        } catch (e: Exception) {
            println("db connection close fail :${e}")
        }
    }

    /**setActiveDb 当dataSource更改后,更新RecordDb
     * @param ds gmodel.dataSource.value
     * @param configName "config"
     */
    fun setRecordDb(configName: String, ds: DataSource, dialect: Dialect): DbPro {
        val config = Config(configName, ds, dialect)
        try {
            DbKit.addConfig(config)
        } catch (e: Exception) {
            println("""DbKit.addConfig(config) failed or the config is already exist""")
        }
        return Db.use(configName)
    }
    fun getSharedObjectMap(engine: Engine): Map<String, Any> {
        val map = ReflectUtil.invoke(engine.getEngineConfig(), "getSharedObjectMap") as Map<String, Any>
        return map
    }

    /**
     * 设置MetaBuilder的removedTableNamePrefixes，excludedTable等参数
     * @param metaBuilder
     * @param removedTableNamePrefixes
     * @param excludedTable
     */
    fun setMetaBuilder(metaBuilder:MetaBuilder, removedTableNamePrefixes:Array<String>, excludedTable:Array<String>):MetaBuilder{
        metaBuilder.setRemovedTableNamePrefixes(*removedTableNamePrefixes)
        metaBuilder.addExcludedTable(*excludedTable)
        metaBuilder.setTypeMapping(TypeMapping())
        return metaBuilder
    }

    fun addSharedObject(engine: Engine, kv: Kv) {
//        val ec = engine.getEngineConfig()
//        val mapOld = ReflectUtil.invoke(ec, "getSharedObjectMap") as Map<String, Any>
//        val sharedObjectMap = ReflectUtil.getField(ec.javaClass, "sharedObjectMap")
//        sharedObjectMap.isAccessible = true
//        var mapNew = Constants.DelKey(Kv().set(mapOld), "jDbPro", "jDb", "gmodel")
//        sharedObjectMap.set(ec, mapNew)

        try {
            kv.forEach { t, _ -> engine.removeSharedObject(t.toString()) }
        } catch (e: Exception) {
            println("""engine.addSharedObject failed ${e}""")
        }finally {
//            kv.forEach { t, u -> ec.addSharedObject(t.toString(), u) }
            kv.forEach { t, u -> engine.addSharedObject(t.toString(), u) }
        }
    }

    /**
     * 生成代码文件
     * @param template
     * @param context
     * @param fileName
     * @param doPrint
     * @throws Exception
     */
    @Throws(Exception::class)
    fun writeFiles(template: Template, context: Kv, fileName: String, doPrint: Boolean) {
        val newPath=FileUtil.touch(fileName)
        val fileWriter = FileWriter(newPath, false)
        template.render(context, fileWriter)
        fileWriter.close()
        if (doPrint) {
            println("write File: $fileName")
        }
    }

    /**
     * 输出到resources目录下 TODO 待实现
     *
     * @param out
     * @return
     */
    fun toOutPath(out: String, content: Kv): String {
        val outPath = toDesktop() + content["projectName"] + "/" + content["baseResourcesPath"] + out
        existFileSys(outPath)
        return outPath
    }

    /**
     * 生成到桌面
     *
     * @return
     */
    fun toDesktop(): String {
        val fsv = FileSystemView.getFileSystemView()
        val com = fsv.homeDirectory // 这便是读取桌面路径的方法了
        return com.path + "/"
    }

    /**
     * 检查创建文件
     *
     * @param outPath
     * @return
     */
    fun existFileSys(outPath: String): Boolean {
        val file = File(outPath)
        if (!file.exists()) {
            file.mkdirs()
        }
        return true
    }

    /**
     * 将传入的所有列表中的元素清空
     * @param ArrayList 列表数组
     * @return 将传入的所有列表中的元素清空后返回
     */
    fun clearLists(vararg lists: ArrayList<*>): ArrayList<*> {
        lists.forEach {
            it.clear()
        }
        return arrayListOf(lists)
    }
}

enum class DbType {
    /**
     * The horizontal (right <-> left) orientation
     */
    HORIZONTAL,

    /**
     * The vertical (top <-> bottom) orientation
     */
    VERTICAL
}


class NowDirective : Directive() {
    override fun exec(env: Env?, scope: com.jfinal.template.stat.Scope?, writer: Writer?) {
        write(writer, Date().toString())
    }
}

class Demo : Directive() {
    // ExprList 代表指令参数表达式列表
    override fun setExprList(exprList: ExprList?) {
        // 在这里可以对 exprList 进行个性化控制
        super.setExprList(exprList)
    }

    override fun exec(env: Env?, scope: com.jfinal.template.stat.Scope?, writer: Writer?) {
        write(writer, "body 执行前\n")
        stat.exec(env, scope, writer)  // 执行 body
        write(writer, "body 执行后\n")
    }

    override fun hasEnd(): Boolean {
        return true  // 返回 true 则该指令拥有 #end 结束标记
    }
}